import axios, {
  type AxiosRequestConfig,
  type AxiosResponse,
  AxiosError,
  type InternalAxiosRequestConfig
} from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '../stores/userStore'
import { loadingStatsStore } from '../stores/statsManageStore'
import router from '../router'

// 定义后端返回数据格式
interface ApiResponse<T = any> {
  code: number
  data: T
  msg: string
}

// 扩展请求配置
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
  showLoading?: boolean // 是否显示加载动画（默认true）
  minLoadingTime?: number // 最小加载时间（确保动画至少播放，默认800ms）
}

// 创建axios实例
const service = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 15000, // 延长超时，避免短时间内错误关闭动画
  headers: {} as any
})

// 加载状态管理：避免重复创建store实例
const getLoadingStore = () => loadingStatsStore()
const getUserStore = () => useUserStore()

// 请求拦截器：只做必要操作，不阻塞主线程
service.interceptors.request.use(
  (config: CustomAxiosRequestConfig): CustomAxiosRequestConfig => {
    // 1. 显示加载动画（默认显示，可通过config关闭）
    if (config.showLoading !== false) {
      const loadingStore = getLoadingStore()
      loadingStore.setLoadingText('加载中...')
      loadingStore.startLoad() // 这里确保是修改响应式状态（如Pinia的state）
    }

    // 2. 添加token（同步操作，不阻塞）
    const token = getUserStore().token
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`
    }

    // 3. 处理GET缓存（同步操作）
    if (config.method?.toUpperCase() === 'GET') {
      config.params = { ...config.params, _t: Date.now() }
    }

    return config
  },
  (error: AxiosError) => {
    // 错误时立即关闭动画（避免冻结状态）
    const loadingStore = getLoadingStore()
    loadingStore.setLoadingText('加载失败')
    
    loadingStore.completeLoad()

    ElMessage.error('请求配置错误：' + (error.message || '未知错误'))
    return Promise.reject(error)
  }
)

// 响应拦截器：处理最小加载时间，确保动画播放完整
service.interceptors.response.use(
  async (response: AxiosResponse<ApiResponse>): Promise<any> => {
    const config = response.config as CustomAxiosRequestConfig
    if (config.showLoading === false) return response.data

    const loadingStore = getLoadingStore()
    const res = response.data
    const minLoadingTime = config.minLoadingTime || 800 // 默认至少播放800ms
    const requestStartTime = (config as any).requestStartTime || Date.now()
    const elapsedTime = Date.now() - requestStartTime

    // 🌟 确保动画至少播放minLoadingTime，用requestAnimationFrame保证渲染
    if (elapsedTime < minLoadingTime) {
      // 用requestAnimationFrame包裹setTimeout，避免阻塞动画线程
      await new Promise(resolve => {
        requestAnimationFrame(() => {
          setTimeout(resolve, minLoadingTime - elapsedTime)
        })
      })
    }

    // 处理业务逻辑
    if (res.code !== 200) {
      loadingStore.setLoadingText('加载失败')
      switch (res.code) {
        case 401:
          ElMessage.error('登录已过期，请重新登录')
          getUserStore().logout()
          router.push('/login')
          break
        case 403:
          ElMessage.error('没有操作权限')
          router.push('/403')
          break
        case 404:
          ElMessage.error('请求的资源不存在')
          break
        default:
          ElMessage.error(res.msg || '操作失败')
      }
      loadingStore.completeLoad()
      return Promise.reject(new Error(res.msg || 'Error'))
    }

    loadingStore.setLoadingText('加载完成')
    await new Promise<void>((resolve)=>{
                setTimeout(()=>{
                    resolve();
                },500)
            })
    loadingStore.completeLoad()
    return res
  },
  async (error: AxiosError) => {
    const config = error.config as CustomAxiosRequestConfig
    if (config?.showLoading === false) return Promise.reject(error)

    const loadingStore = getLoadingStore()
    let errorMsg = '网络请求失败'

    // 错误处理
    if (error.response) {
      switch (error.response.status) {
        case 400: errorMsg = '请求参数错误'; break
        case 401:
          errorMsg = '登录已过期，请重新登录'
          getUserStore().logout()
          router.push('/login')
          break
        case 403: errorMsg = '没有操作权限'; break
        case 404: errorMsg = '请求的接口不存在'; break
        case 500: errorMsg = '服务器内部错误'; break
        default: errorMsg = `请求失败（${error.response.status}）`
      }
    } else if (error.request) {
      errorMsg = '网络连接失败，请检查网络'
    } else {
      errorMsg = error.message || '请求发生未知错误'
    }

    // 确保错误状态下动画也不冻结
    const minLoadingTime = config?.minLoadingTime || 500
    const requestStartTime = (config as any).requestStartTime || Date.now()
    const elapsedTime = Date.now() - requestStartTime

    if (elapsedTime < minLoadingTime) {
      await new Promise(resolve => {
        requestAnimationFrame(() => {
          setTimeout(resolve, minLoadingTime - elapsedTime)
        })
      })
    }

    loadingStore.setLoadingText('网络错误')
    await new Promise<void>((resolve)=>{
                setTimeout(()=>{
                    resolve();
                },500)
            })
    loadingStore.completeLoad()
    ElMessage.error(errorMsg)
    return Promise.reject(error)
  }
)

// 封装请求方法：记录请求开始时间
const request = {
  get<T = any>(url: string, params: any = {}, config: Partial<CustomAxiosRequestConfig> = {}): Promise<T> {
    const requestConfig = {
      ...config,
      requestStartTime: Date.now() // 记录开始时间，用于计算加载时长
    } as CustomAxiosRequestConfig
    return service.get(url, { params, ...requestConfig })
  },
  post<T = any>(url: string, data: any = {}, config: Partial<CustomAxiosRequestConfig> = {}): Promise<T> {
    const requestConfig = {
      ...config,
      requestStartTime: Date.now()
    } as CustomAxiosRequestConfig
    return service.post(url, data, requestConfig)
  },
  put<T = any>(url: string, data: any = {}, config: Partial<CustomAxiosRequestConfig> = {}): Promise<T> {
    const requestConfig = {
      ...config,
      requestStartTime: Date.now()
    } as CustomAxiosRequestConfig
    return service.put(url, data, requestConfig)
  },
  delete<T = any>(url: string, params: any = {}, config: Partial<CustomAxiosRequestConfig> = {}): Promise<T> {
    const requestConfig = {
      ...config,
      requestStartTime: Date.now()
    } as CustomAxiosRequestConfig
    return service.delete(url, { params, ...requestConfig })
  }
}

export default request